home *** CD-ROM | disk | FTP | other *** search
/ Internet Info 1994 March / Internet Info CD-ROM (Walnut Creek) (March 1994).iso / networking / ip / ka9q / src.arc / SMTPSERV.C < prev    next >
C/C++ Source or Header  |  1989-08-19  |  18KB  |  810 lines

  1. /* SMTP Server state machine - see RFC 821
  2.  *  enhanced 4/88 Dave Trulli nn2z
  3.  */
  4. #include <stdio.h>
  5. #include <time.h>
  6. #ifdef UNIX
  7. #include <sys/types.h>
  8. #endif
  9. #if    defined(__STDC__) || defined(__TURBOC__)
  10. #include <stdarg.h>
  11. #endif
  12. #include <ctype.h>
  13. #include <setjmp.h>
  14. #include "global.h"
  15. #include "mbuf.h"
  16. #include "cmdparse.h"
  17. #include "socket.h"
  18. #include "proc.h"
  19. #include "smtp.h"
  20.  
  21. extern char Nospace[];
  22.  
  23. static struct list *expandalias __ARGS((struct list **head,char *user));
  24. static int  getmsgtxt __ARGS((struct smtpsv *mp));
  25. static struct smtpsv *mail_create __ARGS((void));
  26. static char *getname __ARGS((char *cp));
  27. static void mail_clean __ARGS((struct smtpsv *mp));
  28. static int mailit __ARGS((FILE *data,char *from,struct list *tolist));
  29. static int router_queue __ARGS((FILE *data,char *from,struct list *to));
  30. static void smtplog __ARGS((char *fmt,...));
  31. static void smtpserv __ARGS((int s,void *unused,void *p));
  32.  
  33. /* Command table */
  34. static char *commands[] = {
  35.     "helo",
  36. #define    HELO_CMD    0
  37.     "noop",
  38. #define    NOOP_CMD    1
  39.     "mail from:",
  40. #define    MAIL_CMD    2
  41.     "quit",
  42. #define    QUIT_CMD    3
  43.     "rcpt to:",
  44. #define    RCPT_CMD    4
  45.     "help",
  46. #define    HELP_CMD    5
  47.     "data",
  48. #define    DATA_CMD    6
  49.     "rset",
  50. #define    RSET_CMD    7
  51.     NULLCHAR
  52. };
  53.  
  54. /* Reply messages */
  55. static char help[] = "214-Commands:\r\n214-HELO NOOP MAIL QUIT RCPT HELP DATA RSET\r\n214 End\r\n";
  56. static char banner[] = "220 %s SMTP ready\r\n";
  57. static char closing[] = "221 Closing\r\n";
  58. static char ok[] = "250 Ok\r\n";
  59. static char reset[] = "250 Reset state\r\n";
  60. static char sent[] = "250 Sent\r\n";
  61. static char ourname[] = "250 %s, Share and Enjoy!\r\n";
  62. static char enter[] = "354 Enter mail, end with .\r\n";
  63. static char ioerr[] = "452 Temp file write error\r\n";
  64. static char badcmd[] = "500 Command unrecognized\r\n";
  65. static char syntax[] = "501 Syntax error\r\n";
  66. static char needrcpt[] = "503 Need RCPT (recipient)\r\n";
  67. static char unknown[] = "550 <%s> address unknown\r\n";
  68.  
  69. static int Ssmtp = -1; /* prototype socket for service */
  70.  
  71. /* Start up SMTP receiver service */
  72. int
  73. smtp1(argc,argv,p)
  74. int argc;
  75. char *argv[];
  76. void *p;
  77. {
  78.     struct sockaddr_in lsocket;
  79.     int s;
  80.  
  81.     if(Ssmtp != -1){
  82.         freeargs(argc,argv);
  83.         return 0;
  84.     }
  85.     psignal(Curproc,0);    /* Don't keep the parser waiting */
  86.     chname(Curproc,"SMTP listener");
  87.  
  88.     lsocket.sin_family = AF_INET;
  89.     lsocket.sin_addr.s_addr = Ip_addr;
  90.     if(argc < 2)
  91.         lsocket.sin_port = IPPORT_SMTP;
  92.     else
  93.         lsocket.sin_port = atoi(argv[1]);
  94.  
  95.     freeargs(argc,argv);
  96.     Ssmtp = socket(AF_INET,SOCK_STREAM,0);
  97.     bind(Ssmtp,(char *)&lsocket,sizeof(lsocket));
  98.     listen(Ssmtp,1);
  99.     for(;;){
  100.         if((s = accept(Ssmtp,NULLCHAR,(int *)NULL)) == -1)
  101.             break;    /* Service is shutting down */
  102.  
  103.         /* Spawn a server */
  104.         newproc("SMTP server",2048,smtpserv,s,NULL,NULL);
  105.     }
  106.     return 0;
  107. }
  108.  
  109. /* Shutdown SMTP service (existing connections are allowed to finish) */
  110. int
  111. smtp0(argc,argv,p)
  112. int argc;
  113. char *argv[];
  114. void *p;
  115. {
  116.     close_s(Ssmtp);
  117.     Ssmtp = -1;
  118.     return 0;
  119. }
  120.  
  121. static void
  122. smtpserv(s,unused,p)
  123. int s;
  124. void *unused;
  125. void *p;
  126. {
  127.     struct smtpsv *mp;
  128.     char **cmdp,buf[LINELEN],*arg,*cp,*cmd;
  129.     int cnt;
  130.     char address_type;
  131.  
  132.     sockowner(s,Curproc);        /* We own it now */
  133.     log(s,"open SMTP");
  134.  
  135.     if((mp = mail_create()) == NULLSMTPSV){
  136.         printf(Nospace);
  137.         log(s,"close SMTP - no space");
  138.         close_s(s);
  139.         return;
  140.     }
  141.     mp->s = s;
  142.  
  143.     (void) usprintf(s,banner,Hostname);
  144.  
  145. loop:    if ((cnt = recvline(s,buf,sizeof(buf))) == -1) {
  146.         /* He closed on us */
  147.         goto quit;
  148.     }
  149.     if(cnt < 4){
  150.         /* Can't be a legal command */
  151.         usprintf(mp->s,badcmd);
  152.         goto loop;
  153.     }    
  154.     rip(buf);
  155.     cmd = buf;
  156.  
  157.     /* Translate entire buffer to lower case */
  158.     for(cp = cmd;*cp != '\0';cp++)
  159.         *cp = tolower(*cp);
  160.  
  161.     /* Find command in table; if not present, return syntax error */
  162.     for(cmdp = commands;*cmdp != NULLCHAR;cmdp++)
  163.         if(strncmp(*cmdp,cmd,strlen(*cmdp)) == 0)
  164.             break;
  165.     if(*cmdp == NULLCHAR){
  166.         (void) usprintf(mp->s,badcmd);
  167.         goto loop;
  168.     }
  169.     arg = &cmd[strlen(*cmdp)];
  170.     /* Skip spaces after command */
  171.     while(*arg == ' ')
  172.         arg++;
  173.     /* Execute specific command */
  174.     switch(cmdp-commands) {
  175.     case HELO_CMD:
  176.         free(mp->system);
  177.         if((mp->system = strdup(arg)) == NULLCHAR){
  178.             /* If the system is out of memory, just close */
  179.             goto quit;
  180.         } else {
  181.             (void) usprintf(mp->s,ourname,Hostname);
  182.         }
  183.         break;
  184.     case NOOP_CMD:
  185.         (void) usprintf(mp->s,ok);
  186.         break;
  187.     case MAIL_CMD:
  188.         if((cp = getname(arg)) == NULLCHAR){
  189.             (void) usprintf(mp->s,syntax);
  190.             break;
  191.         }
  192.         free(mp->from);
  193.         if((mp->from = strdup(cp)) == NULLCHAR){
  194.             /* If the system is out of memory, just close */
  195.             goto quit;
  196.         } else {
  197.             (void) usprintf(mp->s,ok);
  198.         }
  199.         break;
  200.     case QUIT_CMD:
  201.         (void) usprintf(mp->s,closing);
  202.         goto quit;
  203.     case RCPT_CMD:    /* Specify recipient */
  204.         if((cp = getname(arg)) == NULLCHAR){
  205.             (void) usprintf(mp->s,syntax);
  206.             break;
  207.         }
  208.  
  209.         /* check if address is ok */
  210.         if ((address_type = validate_address(cp)) == BADADDR) {
  211.             (void) usprintf(mp->s,unknown,cp);
  212.             break;
  213.         }
  214.         /* if a local address check for an alias */
  215.         if (address_type == LOCAL)
  216.             expandalias(&mp->to, cp);
  217.         else
  218.             /* a remote address is added to the list */
  219.             addlist(&mp->to, cp, address_type);
  220.  
  221.         (void) usprintf(mp->s,ok);
  222.         break;
  223.     case HELP_CMD:
  224.         (void) usprintf(mp->s,help);
  225.         break;
  226.     case DATA_CMD:
  227.         if(mp->to == NULLLIST)
  228.             (void) usprintf(mp->s,needrcpt);
  229.         else if ((mp->data = tmpfile()) == NULLFILE)
  230.             (void) usprintf(mp->s,ioerr);
  231.          else
  232.             getmsgtxt(mp);
  233.         break;
  234.     case RSET_CMD:
  235.         del_list(mp->to);
  236.         mp->to = NULLLIST;
  237.         (void) usprintf(mp->s,reset);
  238.         break;
  239.     }
  240.     goto loop;
  241.  
  242. quit:
  243.     log(mp->s,"close SMTP");
  244.     close_s(mp->s);
  245.     mail_clean(mp);
  246. }
  247.  
  248. /* read the message text */
  249. static int
  250. getmsgtxt(mp)
  251. struct smtpsv *mp;
  252. {
  253.     char buf[LINELEN];
  254.     register char *p = buf;
  255.     long t;
  256.  
  257.     /* Add timestamp; ptime adds newline */
  258.     time(&t);
  259.     fprintf(mp->data,"Received: ");
  260.     if(mp->system != NULLCHAR)
  261.         fprintf(mp->data,"from %s ",mp->system);
  262.     fprintf(mp->data,"by %s with SMTP\n\tid AA%ld ; %s",
  263.             Hostname, get_msgid(), ptime(&t));
  264.     if(ferror(mp->data)){
  265.         (void) usprintf(mp->s,ioerr);
  266.         return 1;
  267.     } else {
  268.         (void) usprintf(mp->s,enter);
  269.     }
  270.     while(1) {
  271.         if(recvline(mp->s,p,sizeof(buf)) == -1){
  272.             return 1;
  273.         }
  274.         rip(p);
  275.         /* check for end of message ie a . or escaped .. */
  276.         if (*p == '.') {
  277.             if (*++p == '\0') {
  278.                 /* Also sends appropriate response */
  279.                 if (mailit(mp->data,mp->from,mp->to) != 0)
  280.                     (void) usprintf(mp->s,ioerr);
  281.                 else
  282.                     (void) usprintf(mp->s,sent);
  283.                 fclose(mp->data);
  284.                 mp->data = NULLFILE;
  285.                 del_list(mp->to);
  286.                 mp->to = NULLLIST;
  287.                 return 0;
  288.             } else if (!(*p == '.' && *(p+1) == '\0'))
  289.                 p--;
  290.         }
  291.         /* for UNIX mail compatiblity */
  292.         if (strncmp(p,"From ",5) == 0)
  293.             (void) putc('>',mp->data);
  294.         /* Append to data file */
  295.         if(fprintf(mp->data,"%s\n",p) < 0) {
  296.             (void) usprintf(mp->s,ioerr);
  297.             return 1;
  298.         }
  299.  
  300.     }
  301.     return 0;
  302. }
  303.  
  304. /* Create control block, initialize */
  305. static struct smtpsv *
  306. mail_create()
  307. {
  308.     register struct smtpsv *mp;
  309.  
  310.     if((mp = (struct smtpsv *)calloc(1,sizeof(struct smtpsv))) == NULLSMTPSV)
  311.         return NULLSMTPSV;
  312.     return mp;
  313. }
  314.  
  315. /* Free resources, delete control block */
  316. static void
  317. mail_clean(mp)
  318. register struct smtpsv *mp;
  319. {
  320.     if (mp == NULLSMTPSV)
  321.         return;
  322.     free(mp->system);
  323.     free(mp->from);
  324.     if(mp->data != NULLFILE)
  325.         fclose(mp->data);
  326.     del_list(mp->to);
  327.     free((char *)mp);
  328. }
  329.  
  330.  
  331. /* Given a string of the form <user@host>, extract the part inside the
  332.  * brackets and return a pointer to it.
  333.  */
  334. static char *
  335. getname(cp)
  336. register char *cp;
  337. {
  338.     register char *cp1;
  339.  
  340.     if ((cp = strchr(cp,'<')) == NULLCHAR)
  341.         return NULLCHAR;
  342.     cp++;    /* cp -> first char of name */
  343.     if ((cp1 = strchr(cp,'>')) == NULLCHAR)
  344.         return NULLCHAR;
  345.     *cp1 = '\0';
  346.     return cp;
  347. }
  348.  
  349.         
  350. /* General mailit function. It takes a list of addresses which have already
  351. ** been verified and expanded for aliases. Base on the current mode the message
  352. ** is place in an mbox, the outbound smtp queue or the rqueue interface
  353. */
  354. static int
  355. mailit(data,from,tolist)
  356. FILE *data;
  357. char *from;
  358. struct list *tolist;
  359. {
  360.     register struct list *ap;
  361.     register FILE *fp;
  362.     int c;
  363.     char    mailbox[50];
  364.     char    *cp;
  365.     char    *desthost;
  366.     int    fail = 0;
  367.     time_t    t;
  368.  
  369.     if ((Smtpmode & QUEUE) != 0)
  370.         return(router_queue(data,from,tolist));
  371.  
  372.     for(ap = tolist;ap != NULLLIST;ap = ap->next) {
  373.  
  374.         rewind(data);
  375.  
  376.         /* non local mail queue it */
  377.         if (ap->type == DOMAIN) {
  378.             if ((desthost = strchr(ap->val,'@')) != NULLCHAR)
  379.                 desthost++;
  380.             fail = queuejob(data,desthost,ap->val,from);
  381.         } else {
  382.             /* strip off host name */
  383.             if ((cp = strchr(ap->val,'@')) != NULLCHAR)
  384.                 *cp = '\0';
  385.  
  386.             /* truncate long user names */
  387.             if (strlen(ap->val) > MBOXLEN)
  388.                 ap->val[MBOXLEN] = '\0';
  389.  
  390.             /* if mail file is busy save it in our smtp queue
  391.              * and let the smtp daemon try later.
  392.              */
  393.             if (mlock(Mailspool,ap->val))
  394.                 fail = queuejob(data,Hostname,ap->val,from);
  395.             else {
  396.                 sprintf(mailbox,"%s/%s.txt",Mailspool,ap->val);
  397.                 if((fp = fopen(mailbox,APPEND_TEXT)) != NULLFILE) {
  398.                     time(&t);
  399.                     fprintf(fp,
  400.                     "From %s %s",from,ctime(&t));
  401.                     while((c = getc(data)) != EOF)
  402.                         if(putc(c,fp) == EOF)
  403.                             break;
  404.                     if(ferror(fp))
  405.                         fail = 1;
  406.                     else
  407.                         fprintf(fp,"\n");
  408.                     /* Leave a blank line between msgs */
  409.                     fclose(fp);
  410.                     printf("New mail arrived for %s\n",ap->val);
  411.                 } else 
  412.                     fail = 1;
  413.                 (void) rmlock(Mailspool,ap->val);
  414.                 if (fail)
  415.                     break;
  416.                 smtplog("deliver: To: %s From: %s",ap->val,from);
  417.             }
  418.         }
  419.     }
  420.     return fail;
  421. }
  422.  
  423. /* Return Date/Time in Arpanet format in passed string */
  424. char *
  425. ptime(t)
  426. long *t;
  427. {
  428.     /* Print out the time and date field as
  429.      *        "DAY day MONTH year hh:mm:ss ZONE"
  430.      */
  431.     register struct tm *ltm;
  432.     static char tz[4];
  433.     static char str[40];
  434.     char *p;
  435.     static char *days[7] = {
  436.     "Sun","Mon","Tue","Wed","Thu","Fri","Sat" };
  437.  
  438.     static char *months[12] = {
  439.         "Jan","Feb","Mar","Apr","May","Jun",
  440.         "Jul","Aug","Sep","Oct","Nov","Dec" };
  441.  
  442.     /* Read the system time */
  443.     ltm = localtime(t);
  444.  
  445.     if (*tz == '\0')
  446.         if ((p = getenv("TZ")) == NULL)
  447.             strcpy(tz,"GMT");
  448.         else
  449.             strncpy(tz,p,3);
  450.  
  451.     /* rfc 822 format */
  452.     sprintf(str,"%s, %.2d %s %02d %02d:%02d:%02d %.3s\n",
  453.         days[ltm->tm_wday],
  454.         ltm->tm_mday,
  455.         months[ltm->tm_mon],
  456.         ltm->tm_year,
  457.         ltm->tm_hour,
  458.         ltm->tm_min,
  459.         ltm->tm_sec,
  460.         tz);
  461.     return(str);
  462. }
  463.  
  464. long 
  465. get_msgid()
  466. {
  467.     char sfilename[LINELEN];
  468.     char s[20];
  469.     register long sequence = 0;
  470.     FILE *sfile;
  471.  
  472.     sprintf(sfilename,"%s/sequence.seq",Mailqdir);
  473.     sfile = fopen(sfilename,READ_TEXT);
  474.  
  475.     /* if sequence file exists, get the value, otherwise set it */
  476.     if (sfile != NULL) {
  477.         (void) fgets(s,sizeof(s),sfile);
  478.         sequence = atol(s);
  479.     /* Keep it in range of and 8 digit number to use for dos name prefix. */
  480.         if (sequence < 0L || sequence > 99999999L )
  481.             sequence = 0;
  482.         fclose(sfile);
  483.     }
  484.  
  485.     /* increment sequence number, and write to sequence file */
  486.     sfile = fopen(sfilename,WRITE_TEXT);
  487.     fprintf(sfile,"%ld",++sequence);
  488.     fclose(sfile);
  489.     return sequence;
  490. }
  491.  
  492. #ifdef    MSDOS
  493. /* Illegal characters in a DOS filename */
  494. static char baddoschars[] = "\"[]:|<>+=;,";
  495. #endif
  496.  
  497. /* test if mail address is valid */
  498. int
  499. validate_address(s)
  500. char *s;
  501. {
  502.     char *cp;
  503.     int32 addr;
  504.  
  505.     /* if address has @ in it the check dest address */
  506.     if ((cp = strrchr(s,'@')) != NULLCHAR) {
  507.         cp++;
  508.         /* 1st check if its our hostname
  509.         * if not then check the hosts file and see
  510.         * if we can resolve ther address to a know site
  511.         * or one of our aliases
  512.         */
  513.         if (strcmp(cp,Hostname) != 0) {
  514.             if ((addr = mailroute(cp)) == 0
  515.                 && (Smtpmode & QUEUE) == 0)
  516.                 return BADADDR;
  517.             if (addr != Ip_addr)
  518.                 return DOMAIN;
  519.         }
  520.         
  521.         /* on a local address remove the host name part */
  522.         *--cp = '\0';
  523.     }
  524.  
  525.     /* if using an external router leave address alone */
  526.     if ((Smtpmode & QUEUE) != 0)
  527.         return LOCAL;
  528.  
  529.     /* check for the user%host hack */
  530.     if ((cp = strrchr(s,'%')) != NULLCHAR) {
  531.         *cp = '@';
  532.         cp++;
  533.         /* reroute based on host name following the % seperator */
  534.         if (mailroute(cp) == 0)
  535.             return BADADDR;
  536.         else
  537.             return DOMAIN;
  538.     }
  539.  
  540. #ifdef MSDOS    /* dos file name checks */
  541.     /* Check for characters illegal in MS-DOS file names */
  542.     for(cp = baddoschars;*cp != '\0';cp++){
  543.         if(strchr(s,*cp) != NULLCHAR)
  544.             return BADADDR;    
  545.     }
  546. #endif
  547.     return LOCAL;
  548. }
  549.  
  550. /* place a mail job in the outbound queue */
  551. int
  552. queuejob(dfile,host,to,from)
  553. FILE *dfile;
  554. char *host,*to,*from;
  555. {
  556.     FILE *fp;
  557.     char tmpstring[50];
  558.     char prefix[9];
  559.     register int c;
  560.  
  561.     sprintf(prefix,"%ld",get_msgid());
  562.     smtplog("queue job %s To: %s From: %s",prefix,to,from);
  563.     mlock(Mailqdir,prefix);
  564.     sprintf(tmpstring,"%s/%s.txt",Mailqdir,prefix);
  565.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  566.         (void) rmlock(Mailqdir,prefix);
  567.         return 1;
  568.     }
  569.     while((c = getc(dfile)) != EOF)
  570.         if(putc(c,fp) == EOF)
  571.             break;
  572.     if(ferror(fp)){
  573.         fclose(fp);
  574.         (void) rmlock(Mailqdir,prefix);
  575.         return 1;
  576.     }
  577.     fclose(fp);
  578.     sprintf(tmpstring,"%s/%s.wrk",Mailqdir,prefix);
  579.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  580.         (void) rmlock(Mailqdir,prefix);
  581.         return 1;
  582.     }
  583.     fprintf(fp,"%s\n%s\n%s\n",host,from,to);
  584.     fclose(fp);
  585.     (void) rmlock(Mailqdir,prefix);
  586.     return 0;
  587. }
  588.  
  589. /* Deliver mail to the appropriate mail boxes */
  590. static int
  591. router_queue(data,from,to)
  592. FILE *data;
  593. char *from;
  594. struct list *to;
  595. {
  596.     int c;
  597.     register struct list *ap;
  598.     FILE *fp;
  599.     char tmpstring[50];
  600.     char prefix[9];
  601.  
  602.     sprintf(prefix,"%ld",get_msgid());
  603.     mlock(Routeqdir,prefix);
  604.     sprintf(tmpstring,"%s/%s.txt",Routeqdir,prefix);
  605.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  606.         (void) rmlock(Routeqdir,prefix);
  607.         return 1;
  608.     }
  609.     rewind(data);
  610.     while((c = getc(data)) != EOF)
  611.         if(putc(c,fp) == EOF)
  612.             break;
  613.     if(ferror(fp)){
  614.         fclose(fp);
  615.         (void) rmlock(Routeqdir,prefix);
  616.         return 1;
  617.     }
  618.     fclose(fp);
  619.     sprintf(tmpstring,"%s/%s.wrk",Routeqdir,prefix);
  620.     if((fp = fopen(tmpstring,WRITE_TEXT)) == NULLFILE) {
  621.         (void) rmlock(Routeqdir,prefix);
  622.         return 1;
  623.     }
  624.     fprintf(fp,"From: %s\n",from);
  625.     for(ap = to;ap != NULLLIST;ap = ap->next) {
  626.         fprintf(fp,"To: %s\n",ap->val);
  627.     }
  628.     fclose(fp);
  629.     (void) rmlock(Routeqdir,prefix);
  630.     smtplog("rqueue job %s From: %s",prefix,from);
  631.     return 0;
  632. }
  633.  
  634. /* add an element to the front of the list pointed to by head 
  635. ** return NULLLIST if out of memory.
  636. */
  637. struct list *
  638. addlist(head,val,type)
  639. struct list **head;
  640. char *val;
  641. int type;
  642. {
  643.     register struct list *tp;
  644.  
  645.     tp = (struct list *)calloc(1,sizeof(struct list));
  646.     if (tp == NULLLIST)
  647.         return NULLLIST;
  648.  
  649.     tp->next = NULLLIST;
  650.  
  651.     /* allocate storage for the char string */
  652.     if ((tp->val = strdup(val)) == NULLCHAR) {
  653.         (void) free((char *)tp);
  654.         return NULLLIST;
  655.     }
  656.     tp->type = type;
  657.  
  658.     /* add entry to front of existing list */
  659.     if (*head == NULLLIST)
  660.         *head = tp;
  661.     else {
  662.         tp->next = *head;
  663.         *head = tp;
  664.     }
  665.     return tp;
  666.  
  667. }
  668.  
  669. #define SKIPWORD(X) while(*X && *X!=' ' && *X!='\t' && *X!='\n' && *X!= ',') X++;
  670. #define SKIPSPACE(X) while(*X ==' ' || *X =='\t' || *X =='\n' || *X == ',') X++;
  671.  
  672. /* check for and alias and expand alias into a address list */
  673. static struct list *
  674. expandalias(head, user)
  675. struct list **head;
  676. char *user;
  677. {
  678.     FILE *fp;
  679.     register char *s,*p;
  680.     int inalias;
  681.     struct list *tp;
  682.     char buf[LINELEN];
  683.     
  684.         /* no alias file found */
  685.     if ((fp = fopen(Alias, READ_TEXT)) == NULLFILE)
  686.         return addlist(head, user, LOCAL);
  687.  
  688.     inalias = 0;
  689.     while (fgets(buf,LINELEN,fp) != NULLCHAR) {
  690.         p = buf;
  691.         if ( *p == '#' || *p == '\0')
  692.             continue;
  693.         rip(p);
  694.  
  695.         /* if not in an matching entry skip continuation lines */
  696.         if (!inalias && isspace(*p))
  697.             continue;
  698.  
  699.         /* when processing an active alias check for a continuation */
  700.         if (inalias) {
  701.             if (!isspace(*p)) 
  702.                 break;    /* done */
  703.         } else {
  704.             s = p;
  705.             SKIPWORD(p);
  706.             *p++ = '\0';    /* end the alias name */
  707.             if (strcmp(s,user) != 0)
  708.                 continue;    /* no match go on */
  709.             inalias = 1;
  710.         }
  711.  
  712.         /* process the recipients on the alias line */
  713.         SKIPSPACE(p);
  714.         while(*p != '\0' && *p != '#') {
  715.             s = p;
  716.             SKIPWORD(p);
  717.             if (*p != '\0')
  718.                 *p++ = '\0';
  719.  
  720.             /* find hostname */
  721.             if (strchr(s,'@') != NULLCHAR)
  722.                 tp = addlist(head,s,DOMAIN);
  723.             else
  724.                 tp = addlist(head,s,LOCAL);
  725.             SKIPSPACE(p);
  726.         }
  727.     }
  728.     (void) fclose(fp);
  729.  
  730.     if (inalias)    /* found and processed and alias. */
  731.         return tp;
  732.  
  733.     /* no alias found treat as a local address */
  734.     return addlist(head, user, LOCAL);
  735. }
  736.  
  737. #ifdef    ANSIPROTO
  738. static void
  739. smtplog(char *fmt, ...)
  740. {
  741.     va_list ap;
  742.     char *cp;
  743.     long t;
  744.     FILE *fp;
  745.  
  746.     if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
  747.         return;
  748.     time(&t);
  749.     cp = ctime(&t);
  750.     rip(cp);
  751.     fprintf(fp,"%s ",cp);
  752.     va_start(ap,fmt);
  753.     vfprintf(fp,fmt,ap);
  754.     va_end(ap);
  755.     fprintf(fp,"\n");
  756.     fclose(fp);
  757. }
  758.  
  759. #else
  760.  
  761. static void
  762. smtplog(fmt,arg1,arg2,arg3,arg4)
  763. char *fmt;
  764. int arg1,arg2,arg3,arg4;
  765. {
  766.     char *cp;
  767.     long t;
  768.     FILE *fp;
  769.  
  770.     if ((fp = fopen(Maillog,APPEND_TEXT)) == NULLFILE)
  771.         return;
  772.     time(&t);
  773.     cp = ctime(&t);
  774.     rip(cp);
  775.     fprintf(fp,"%s ",cp);
  776.     fprintf(fp,fmt,arg1,arg2,arg3,arg4);
  777.     fprintf(fp,"\n");
  778.     fclose(fp);
  779. }
  780. #endif
  781.  
  782. /* send mail to a single user. Can be called from the ax24 mailbox or
  783. ** from the return mail function in the smtp client 
  784. */
  785. int
  786. mailuser(data,from,to)
  787. FILE *data;
  788. char *from;
  789. char *to;
  790. {
  791.  
  792.         int address_type, ret;
  793.         struct list *tolist = NULLLIST;
  794.  
  795.         /* check if address is ok */
  796.         if ((address_type = validate_address(to)) == BADADDR) {
  797.             return 1;
  798.         }
  799.         /* if a local address check for an alias */
  800.         if (address_type == LOCAL)
  801.             expandalias(&tolist, to);
  802.         else
  803.             /* a remote address is added to the list */
  804.             addlist(&tolist, to, address_type);
  805.         ret = mailit(data,from,tolist);
  806.         del_list(tolist);
  807.         return ret;
  808.  
  809. }
  810.